package com.playfair.thread;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Iterator;

import com.playfair.components.Digraph;
import com.playfair.components.Matrix;
import com.playfair.core.AppCore;
import com.playfair.thread.utils.BruteForceAttackResult;

public class BruteForceAttackerTrigrams implements Runnable {

	private Thread runner;

	public BruteForceAttackerTrigrams(String file, int nmb, int fileNmb) {
		runner = new Thread(this, file + nmb + "\\" + fileNmb);
		System.out.println("THREAD CREATED: " + runner.getName());
	}

	private Double probability(String code) {
		HashMap<String, Double> currentTrigrams = new HashMap<String, Double>();
		int n = code.length(), nmb = 0;
		Double value = new Double(0), tmp = new Double(0);
		for (int i = 0; i < n - 3; i++) {
			String trigram = code.substring(i, i + 3);
			if (currentTrigrams.containsKey(trigram)) {
				currentTrigrams
						.put(trigram, currentTrigrams.get(trigram) + 1.0);
			} else {
				currentTrigrams.put(trigram, 1.0);
			}

			nmb++;
		}
		// System.out.println(currentTrigrams.size());
		Iterator<String> it = currentTrigrams.keySet().iterator();
		while (it.hasNext()) {

			String trg = (String) it.next();
			currentTrigrams.put(trg, currentTrigrams.get(trg) / nmb);
			// it.remove();
		}
		// System.out.println(currentTrigrams.size());
		it = currentTrigrams.keySet().iterator();
		while (it.hasNext()) {
			// System.out.println(5);
			String trg = (String) it.next();
			if (AppCore.getInstance().getTrigrams().containsKey(trg)) {
				tmp = currentTrigrams.get(trg)
						- AppCore.getInstance().getTrigrams().get(trg);
			} else {
				tmp = currentTrigrams.get(trg);
			}
			value += (tmp * tmp);
			it.remove();
		}
		return value;
	}

	@Override
	public void run() {
		Matrix currentMatrix;
		String line;
		Digraph digraph = new Digraph(AppCore.getInstance().getCodeToBreak());// ==========
		FileInputStream fis2 = null;
		BufferedReader br2 = null;
		Double bestValue = new Double(100000);

		try {
			fis2 = new FileInputStream(runner.getName());
			br2 = new BufferedReader(new InputStreamReader(fis2,
					Charset.forName("UTF-8")));

			while ((line = br2.readLine()) != null) {
				line = line.toUpperCase();
				currentMatrix = new Matrix(line.trim());
				String plainText = AppCore.getInstance().decrypt(currentMatrix,
						digraph);

				Double currentValue = probability(plainText);
				if (currentValue <= bestValue) {
					AppCore.getInstance()
							.getPossibleSolutions()
							.add(new BruteForceAttackResult("key: " + line
									+ ", text: " + plainText, currentValue));
					bestValue = currentValue;
				}
			}
			br2.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		System.out.println("THREAD DONE: " + runner.getName());

	}

}
